package iputil

import (
	"net"
	"net/http"
	"strings"

	"gitee.com/tomatomeatman/golang-repository/bricks/utils/ginutil"
	Log "github.com/cihub/seelog"
)

type IpUtil struct{}

// 获取访问IP
func (iu IpUtil) GetIP(ctx ginutil.Context) string {
	ip := ctx.Request.Header.Get("X-Real-IP")
	if net.ParseIP(ip) != nil {
		return ip
	}

	ip = ctx.Request.Header.Get("X-Forward-For")
	for _, i := range strings.Split(ip, ",") {
		if net.ParseIP(i) != nil {
			return ip
		}
	}

	ip, _, err := net.SplitHostPort(ctx.Request.RemoteAddr)
	if err != nil {
		Log.Error("获取访问IP地址发生异常:", err) //使用localhost会得到这个IP
		return "0.0.0.0"
	}

	if net.ParseIP(ip) == nil {
		return ip
	}

	if "0:0:0:0:0:0:0:1" == ip {
		ip = "127.0.0.1"
	} else if "::1" == ip {
		ip = "127.0.0.1"
	}

	if "127.0.0.1" != ip {
		return ip
	}

	result, err := IpUtil{}.GetOutBoundIP()
	if err != nil {
		return ip
	}

	return result
}

// 获取本机ip地址
func (iu IpUtil) GetOutBoundIP() (ip string, err error) {
	conn, err := net.Dial("udp", "8.8.8.8:53")
	if err != nil {
		Log.Error("获取本地IP地址发生异常:", err)
		return
	}

	localAddr := conn.LocalAddr().(*net.UDPAddr)
	ip = strings.Split(localAddr.String(), ":")[0]

	return
}

// 获取请求中的IP
func (iu IpUtil) RemoteIp(req *http.Request) string {
	remoteAddr := req.Header.Get("X-Real-IP")
	if net.ParseIP(remoteAddr) == nil {
		remoteAddr = ""
	}

	if remoteAddr == "" {
		remoteAddr = req.Header.Get("X-Forward-For")
		for _, i := range strings.Split(remoteAddr, ",") {
			if net.ParseIP(i) == nil {
				remoteAddr = ""
			}
		}
	}

	if remoteAddr == "" {
		temp, _, err := net.SplitHostPort(req.RemoteAddr)
		if err != nil {
			remoteAddr = ""
		}

		remoteAddr = temp
	}

	if net.ParseIP(remoteAddr) == nil {
		remoteAddr = ""
	}

	if remoteAddr == "::1" || remoteAddr == "" {
		remoteAddr = "127.0.0.1"
	}

	if remoteAddr == "127.0.0.1" {
		//remoteAddr = GetLocalIpV4()
		remoteAddr = iu.GetLocal()
	}

	return remoteAddr
}

// getLocalIpV4 获取 IPV4 IP，没有则返回空
// 有返回虚拟网卡的风险
func (iu IpUtil) GetLocalIpV4() string {
	netInterfaces, err := net.Interfaces()
	if err != nil {
		panic(err)
	}

	for i := 0; i < len(netInterfaces); i++ {
		if (netInterfaces[i].Flags & net.FlagUp) == 0 {
			continue
		}

		flags := netInterfaces[i].Flags.String()
		if !strings.Contains(flags, "up") || !strings.Contains(flags, "broadcast") {
			continue //对于服务器而言，只会有一个网卡处于 up 且 broadcast 状态
		}

		addrs, _ := netInterfaces[i].Addrs()

		for _, address := range addrs {
			if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsLinkLocalUnicast() {
				Log.Error(ipnet.IP.IsLinkLocalUnicast())
				if ipnet.IP.To4() == nil {
					continue
				}

				return ipnet.IP.String()
			}
		}
	}

	return ""
}

// 获取当前本地使用的主IP地址
func (iu IpUtil) GetLocal() string {
	conn, err := net.Dial("udp", "8.8.8.8:8") //使用UDP协议,需要担心访问不到8.8.8.8:8
	if err != nil {
		panic(err)
	}

	defer conn.Close()
	localAddr := conn.LocalAddr().(*net.UDPAddr)

	return localAddr.IP.String()
}

// 判断指定端口是否空闲,空闲返回true
// 利用Go标准库中的net包和错误处理来判断端口是否可用
func (iu IpUtil) IsPortAvailable(port string) bool {
	listener, err := net.Listen("tcp", ""+port)
	if err != nil {
		if opErr, ok := err.(*net.OpError); ok && opErr.Err.Error() == "listen tcp :8080: bind: address already in use" {
			return false // 端口被占用
		}
		// 其他错误处理...
		return false
	}

	defer func(li net.Listener) {
		err := li.Close()
		if err != nil {
			Log.Error("Error closing listener:", err)
		}
	}(listener) // 关闭监听器以防资源泄露

	return true // 端口可用
}
